/**
 * 
 */
package com.suman.bbcticker.service;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.widget.RemoteViews;

import com.suman.bbcticker.ApplicationStateObjectsHolder;
import com.suman.bbcticker.FeedItem;
import com.suman.bbcticker.R;
import com.suman.bbcticker.RssFeed;
import com.suman.bbcticker.activity.FindOutMoreActivity;
import com.suman.bbcticker.configure.PreferenceLauncherActivity;
import com.suman.bbcticker.configure.RssFeedPreference;
import com.suman.bbcticker.parser.RssFeedHandler;
import com.suman.bbcticker.weather.GoogleWeatherService;

/**
 * @author ShivakP
 */
public class RssReaderService extends Service {
	private static final String SPACE_SEPARATOR = "   ";
	public static final String FEED_FOR_FIRST_TIME = "Feed For FirstTime";
	private static final String TAG = "RssReaderService";
	protected static final String PACKAGE_NAME_FOR_MSG_HANDLER = null;
	public static String CURRENT_FEED = "CURRENT_FEED";
	public static String SITE_BBC_NEWS = "SITE_BBCNEWS";

	private static int notificationId = 0;
	private static String NETWORK_PROB_TEXT = "Sorry for Inconvenience.Please Wait.Waiting for Network Connection to become available.";

	@Override
	public void onStart(Intent intent, int startId) {
		try {

			Bundle extras = intent.getExtras();
			int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
			if (extras != null) {
				mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
			}
			AppDataHolder appDataHolder = new AppDataHolder();
			appDataHolder.setAppWidgetId(mAppWidgetId);
			appDataHolder.setContext(this);
			appDataHolder.setIntent(intent);			
			new RssFeedInvokerTask().execute(appDataHolder);

		} catch (Throwable e) {
			Log.e(TAG, "Some throwable.." + e);
		}

	}

	public RemoteViews buildUpdate(int appWidgetId) {
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		RssFeedPreference rssFeedPreference = ApplicationStateObjectsHolder.preferenceHashMap.get(appWidgetId);
		Context context = this;
		boolean feedAlert = rssFeedPreference.getNotificationEnabled();
		

		String currentFeed = sharedPreferences.getString(PreferenceLauncherActivity.PREF_PREFIX_KEY + appWidgetId + CURRENT_FEED,
				FEED_FOR_FIRST_TIME);

		String rssFeedUrl = rssFeedPreference.getSelectedSite();
		String webPageUrl = "http://www.bbc.co.uk";
		String widgetImage = SITE_BBC_NEWS;

		String feedRefreshTime = rssFeedPreference.getFeedRefreshTime();
		RssFeed rssFeed = invokeRssFeedService(rssFeedUrl, appWidgetId, feedRefreshTime);
		
		//new WebpageStreamDownloadTask().execute

		rssFeedPreference.setCurrentRssFeedObject(rssFeed);
		StringBuffer completeFeed = transformRssFeedToString(rssFeed);
		RemoteViews updateViews = null;

		if (completeFeed != null) {
			// This is when some problem with network happens and nothing comes
			// back
			if ("".equalsIgnoreCase(completeFeed.toString())) {

				updateViews = doActionWhenHostIsResolved(context, appWidgetId, rssFeedPreference, feedAlert, currentFeed, webPageUrl,
						widgetImage, new StringBuffer(NETWORK_PROB_TEXT), rssFeed);

			} else {
				updateViews = doActionWhenHostIsResolved(context, appWidgetId, rssFeedPreference, feedAlert, currentFeed, webPageUrl,
						widgetImage, completeFeed, rssFeed);
			}

		}

		return updateViews;

	}

	private RemoteViews doActionWhenHostIsResolved(Context context, int appWidgetId, RssFeedPreference rssFeedPreference,
			boolean feedAlert, String currentFeed, String webPageUrl, String widgetImage, StringBuffer completeFeed, RssFeed rssFeed) {
		RemoteViews updateViews;
		updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);

		updateViews.setTextViewText(R.id.word_title, completeFeed.toString());
		// TODO do we need to call this again and again???
		setupFeedSiteIcon(context, appWidgetId, updateViews, rssFeed);

		// launching config icon
		setupConfigIcon(context, appWidgetId, updateViews);

		// launching Refresh icon
		setupRefreshIcon(context, appWidgetId, updateViews);
		
		setUpFindMoreIcon(context,appWidgetId,updateViews);

		raiseNotificationAndsavePrefs(appWidgetId, rssFeedPreference, feedAlert, currentFeed, completeFeed, rssFeed);
		return updateViews;
	}

	private void setUpFindMoreIcon(Context context, int appWidgetId, RemoteViews updateViews) {
		//updateViews.setImageViewResource(R.id.findoutmoreicon, R.drawable.findmore);
		// TODO Auto-generated method stub
		
		Intent findOutMoreActivityIntent = new Intent(this, FindOutMoreActivity.class);
		findOutMoreActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		findOutMoreActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		findOutMoreActivityIntent.setData((Uri.parse("foobar://" + SystemClock.elapsedRealtime())));

		PendingIntent findOutMoreActivityPendingIntent = PendingIntent.getActivity(context, 0,
				findOutMoreActivityIntent, 0);
		updateViews.setOnClickPendingIntent(R.id.findoutmoreicon, findOutMoreActivityPendingIntent);
		updateViews.setImageViewResource(R.id.findoutmoreicon, R.drawable.findmore);
		
		
	}

	private void setupFeedSiteIcon(Context context, int appWidgetId, RemoteViews updateViews,RssFeed rssFeed) {
		//new WebpageStreamDownloadTask().execute
		FavIconDownloadAsyncTaskParamAndResult favIconDownloadAsyncTaskParamAndResult = new FavIconDownloadAsyncTaskParamAndResult();
		favIconDownloadAsyncTaskParamAndResult.setRemoteViews(updateViews);
		favIconDownloadAsyncTaskParamAndResult.setRssFeedLinkUrl(rssFeed.getFeedList().get(0).getLink());
		favIconDownloadAsyncTaskParamAndResult.setAppWidgetId(appWidgetId);
		favIconDownloadAsyncTaskParamAndResult.setContext(context);
		new FavIconDownloadAsyncTask().execute(favIconDownloadAsyncTaskParamAndResult);
	}

	private void setupRefreshIcon(Context context, int appWidgetId, RemoteViews updateViews) {
		Intent feedTickerRefreshServiceIntent = new Intent(this, RefreshService.class);
		feedTickerRefreshServiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		feedTickerRefreshServiceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		feedTickerRefreshServiceIntent.setData((Uri.parse("foobar://" + SystemClock.elapsedRealtime())));

		PendingIntent feedTickerRefreshServicePendingIntent = PendingIntent.getService(context, 0, feedTickerRefreshServiceIntent, 0);
		updateViews.setOnClickPendingIntent(R.id.refreshicon, feedTickerRefreshServicePendingIntent);
		updateViews.setImageViewResource(R.id.refreshicon, R.drawable.refresh);
	}

	private void setupConfigIcon(Context context, int appWidgetId, RemoteViews updateViews) {
		Intent feedTickerPreferencesActivityIntent = new Intent(this, PreferenceLauncherActivity.class);
		feedTickerPreferencesActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		feedTickerPreferencesActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
		feedTickerPreferencesActivityIntent.setData((Uri.parse("foobar://" + SystemClock.elapsedRealtime())));

		PendingIntent feedTickerPreferencesActivityPendingIntent = PendingIntent.getActivity(context, 0,
				feedTickerPreferencesActivityIntent, 0);
		updateViews.setOnClickPendingIntent(R.id.configicon, feedTickerPreferencesActivityPendingIntent);
		updateViews.setImageViewResource(R.id.configicon, R.drawable.configicon);
	}

	private void raiseNotificationAndsavePrefs(int appWidgetId, RssFeedPreference rssFeedPreference, boolean feedAlert, String currentFeed,
			StringBuffer completeFeed, RssFeed currentRssFeedObj) {
		if (feedAlert) {

			// Dont raise an alert when system boots up initially(After adding
			// widget)
			String[] changedFeedItemsAsArray = getArrayRepresentationForChangedFeed(currentFeed, completeFeed.toString());			
			if (doWeNeedToNotifyUser(currentFeed, completeFeed, changedFeedItemsAsArray)) {
				List<FeedItem> feedChangeList = new ArrayList<FeedItem>();
				for (String changedFeedAsString : changedFeedItemsAsArray) {
					FeedItem feedItem = currentRssFeedObj.getFeedItemBasedOnTitle(changedFeedAsString.trim());
					if (checkForNull(feedItem)) {
						feedChangeList.add(feedItem);

					}
				}

				if (feedChangeList.size() > 0) {
					raiseNotification(rssFeedPreference, feedChangeList);
				}

			}

		}
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		SharedPreferences.Editor editPrefs = sharedPreferences.edit();
		editPrefs.putString(PreferenceLauncherActivity.PREF_PREFIX_KEY + appWidgetId + CURRENT_FEED, completeFeed.toString());
		editPrefs.commit();

	}

	private void raiseNotification(RssFeedPreference rssFeedPreference, List<FeedItem> feedChangeList) {

		boolean notificationSelected = rssFeedPreference.getNotificationEnabled();
		if (notificationSelected) {
			boolean notificationSound = rssFeedPreference.getSoundNotification();
			boolean notificationVibrate = rssFeedPreference.getVibrateNotification();
			String alertKeyword = rssFeedPreference.getAlertKeyword();

			Log.e(TAG, "notificationSound and notificationVibrate are.." + notificationSound + "," + notificationVibrate);

			NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			for (FeedItem changedFeedItem : feedChangeList) {

				if (feedMatchesKeyword(changedFeedItem.getTitle(), alertKeyword)) {
					Notification notification = new Notification(R.drawable.alert_small, changedFeedItem.getTitle(), System.currentTimeMillis());
					RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.widget_notification);
					contentView.setTextViewText(R.id.newswidgetnotificationheadline, changedFeedItem.getTitle());
					contentView.setTextViewText(R.id.newswidgetnotificationdescription, changedFeedItem.getDescription());
					notification.contentView = contentView;
					if (changedFeedItem.getLink() != null) {
						Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(changedFeedItem.getLink()));
						PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, defineIntent, 0);
						notification.contentIntent = pendingIntent;
					}
					if (notificationSound) {
						notification.defaults |= Notification.DEFAULT_SOUND;
					}
					if (notificationVibrate) {
						notification.defaults |= Notification.DEFAULT_VIBRATE;
					}
					notification.flags |= Notification.FLAG_AUTO_CANCEL;
					nm.notify(R.string.app_notification_id + (++notificationId), notification);
				}

			}
		}

	}

	/**
	 * This method checks if user has configured keyword based alert and checks to see if the feedtitle matches
	 * something in the keyword.
	 * @param feedTitle
	 * @param alertKeyword
	 * @return
	 */
	private boolean feedMatchesKeyword(String feedTitle, String alertKeyword) {
		if ("*".equalsIgnoreCase(alertKeyword) || (feedTitle != null && feedTitle.contains(alertKeyword))) {
			return true;
		}
		return false;
	}

	private boolean checkForNull(FeedItem changedFeedItem) {
		return (changedFeedItem != null && changedFeedItem.getDescription() != null && changedFeedItem.getTitle() != null && changedFeedItem
				.getLink() != null);

	}

	private boolean doWeNeedToNotifyUser(String currentFeed, StringBuffer completeFeed, String[] changedFeedItemsAsArray) {
		return changedFeedItemsAsArray != null && changedFeedItemsAsArray.length > 0 && !FEED_FOR_FIRST_TIME.equalsIgnoreCase(currentFeed)
				&& !completeFeed.toString().startsWith(NETWORK_PROB_TEXT) && !currentFeed.toString().startsWith(NETWORK_PROB_TEXT);
	}

	private String[] getArrayRepresentationForChangedFeed(String currentFeed, String completeFeed) {
		String[] currentFeedAsTokens = currentFeed.split("\\s{3}");
		String[] completeFeedAsTokens = completeFeed.split("\\s{3}");
		ArrayList<String> currentFeedAsTokensAsList = new ArrayList<String>(Arrays.asList(currentFeedAsTokens));
		ArrayList<String> completeFeedAsTokensAsList = new ArrayList<String>(Arrays.asList(completeFeedAsTokens));
		completeFeedAsTokensAsList.removeAll(currentFeedAsTokensAsList);
		String[] array = (String[]) completeFeedAsTokensAsList.toArray(new String[completeFeedAsTokensAsList.size()]);

		return array;
	}

	protected StringBuffer transformRssFeedToString(RssFeed rssFeed) {
		StringBuffer completeFeed = new StringBuffer();
		if (rssFeed != null) {
			for (FeedItem feedItem : rssFeed.getFeedList()) {
				String formattedString = MessageFormat.format("<a href=\"{0}\">{1}</a>  ", feedItem.getLink(), feedItem.getTitle());
				Spanned fromHtml = Html.fromHtml(formattedString);
				completeFeed.append(fromHtml);
				completeFeed.append(SPACE_SEPARATOR);
			}
		}
		return completeFeed;
	}

	private RssFeed invokeRssFeedService(String rssFeedUrl, int mAppWidgetId, String feedRefreshTime) {
		Log.e(TAG, "Invoking remote service...");
		RssFeed rssFeed = null;
		if (!"".equalsIgnoreCase(rssFeedUrl)) {

			RssFeedHandler rssFeedHandler = new RssFeedHandler();
			try {
				rssFeed = rssFeedHandler.createFeed(new URL(rssFeedUrl));
				updateAlarmTriggermap(mAppWidgetId, Integer.parseInt(feedRefreshTime));
			} catch (MalformedURLException e) {
				Log.e(TAG, "Malformed URl Exception", e);
			} catch (Throwable e) {
				updateAlarmTriggermap(mAppWidgetId, 0);
				Log.e(TAG, "Some throwable exception", e);
				e.printStackTrace();
			}
		}
		return rssFeed;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Service#onBind(android.content.Intent)
	 */
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	private class RssFeedInvokerTask extends AsyncTask<AppDataHolder, Void, AppDataHolder> {
		@Override
		protected void onPostExecute(AppDataHolder appDataHolder) {
			try {

				if (appDataHolder.getRemoteViews() != null) {
					AppWidgetManager manager = AppWidgetManager.getInstance(appDataHolder.getContext());
					manager.updateAppWidget(appDataHolder.getAppWidgetId(), appDataHolder.getRemoteViews());
				}

			} catch (Throwable t) {
				Log.e(TAG, "Some throwable exception", t);
			}

		}

		@Override
		protected AppDataHolder doInBackground(AppDataHolder... appDataHolderParamArray) {
			AppDataHolder appDataHolder = new AppDataHolder();
			try {

				AppDataHolder appDataHolderParam = appDataHolderParamArray[0];
				Bundle extras = appDataHolderParam.getIntent().getExtras();
				int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
				if (extras != null) {
					mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
				}
				RemoteViews remoteViews = buildUpdate(mAppWidgetId);
				appDataHolder.setRemoteViews(remoteViews);
				appDataHolder.setIntent(appDataHolderParam.getIntent());
				appDataHolder.setContext(appDataHolderParam.getContext());
				appDataHolder.setAppWidgetId(mAppWidgetId);

			} catch (Throwable t) {
				Log.e(TAG, "Some throwable exception", t);
			}
			return appDataHolder;

		}

	}

	private class AppDataHolder {
		private RemoteViews remoteViews;
		private Intent intent;
		private Context context;
		private int appWidgetId;

		public void setRemoteViews(RemoteViews remoteViews) {
			this.remoteViews = remoteViews;
		}

		public RemoteViews getRemoteViews() {
			return remoteViews;
		}

		public void setIntent(Intent intent) {
			this.intent = intent;
		}

		public Intent getIntent() {
			return intent;
		}

		public void setContext(Context context) {
			this.context = context;
		}

		public Context getContext() {
			return context;
		}

		public void setAppWidgetId(int appWidgetId) {
			this.appWidgetId = appWidgetId;
		}

		public int getAppWidgetId() {
			return appWidgetId;
		}

	}

	private void updateAlarmTriggermap(int appWidgetId, int feedRefreshTimeInMins) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, feedRefreshTimeInMins);
		Date nextAlarmTriggerTime = calendar.getTime();
		ApplicationStateObjectsHolder.alarmTriggerTimeMap.put(appWidgetId, nextAlarmTriggerTime);
	}
	
	private class FavIconDownloadAsyncTask extends
	AsyncTask<FavIconDownloadAsyncTaskParamAndResult, Void, FavIconDownloadAsyncTaskParamAndResult> {
			@Override
			protected void onPostExecute(FavIconDownloadAsyncTaskParamAndResult favIconDownloadTaskParamAndResult) {
				if(favIconDownloadTaskParamAndResult.getFavIconDownloadUrl()!=null){
					
					Intent displayNewsActivityIntent = new Intent(favIconDownloadTaskParamAndResult.getContext(), DisplayNewsActivity.class);
					displayNewsActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
					displayNewsActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, favIconDownloadTaskParamAndResult.getAppWidgetId());
					displayNewsActivityIntent.setData((Uri.parse("foobar://" + SystemClock.elapsedRealtime())));
			
					PendingIntent pendingIntent = PendingIntent.getActivity(favIconDownloadTaskParamAndResult.getContext(), 0, displayNewsActivityIntent, 0);
					favIconDownloadTaskParamAndResult.getRemoteViews().setOnClickPendingIntent(R.id.icon, pendingIntent);
					
					Bitmap bitmap = null;
					try {
						bitmap = BitmapUtils.loadBitmap(favIconDownloadTaskParamAndResult.getFavIconDownloadUrl());
						favIconDownloadTaskParamAndResult.getRemoteViews().setImageViewBitmap(R.id.icon, bitmap);
					} catch (MalformedURLException e) {						
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Problem With Loading BITMAP for Favicon
						//Make sure U load custom RSS icon if you can't retrieve it
						favIconDownloadTaskParamAndResult.getRemoteViews().setImageViewResource(R.id.icon, R.drawable.bbcnews_logo);
						e.printStackTrace();
					} catch (Throwable e) {						
						e.printStackTrace();
					}
					
					AppWidgetManager manager = AppWidgetManager.getInstance(favIconDownloadTaskParamAndResult.getContext());
					manager.updateAppWidget(favIconDownloadTaskParamAndResult.getAppWidgetId(), favIconDownloadTaskParamAndResult.getRemoteViews());					
				}	
			}
			
			@Override
			protected FavIconDownloadAsyncTaskParamAndResult doInBackground(FavIconDownloadAsyncTaskParamAndResult... favIconDownloadTaskParamAndResult) {				
					return parseFeedLinkStoryBodyForFavIconUrl(favIconDownloadTaskParamAndResult[0]);			
			}

			private FavIconDownloadAsyncTaskParamAndResult parseFeedLinkStoryBodyForFavIconUrl(FavIconDownloadAsyncTaskParamAndResult favIconDownloadAsyncTaskParamAndResult) {
				
				try {
					URL url = new URL(favIconDownloadAsyncTaskParamAndResult.getRssFeedLinkUrl());
					
					String hostName = url.getHost();
					String favIconDownloadUrl = "http://"+hostName+"/favicon.ico";
					favIconDownloadAsyncTaskParamAndResult.setFavIconDownloadUrl(favIconDownloadUrl);
					Log.e(TAG, "favicon is.." + favIconDownloadUrl);
					
					} catch (MalformedURLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				

				return favIconDownloadAsyncTaskParamAndResult;
			}

}
	
	private class FavIconDownloadAsyncTaskParamAndResult{
		private RemoteViews remoteViews;
		private String favIconDownloadUrl;
		private String rssFeedLinkUrl;
		private Context context;
		private int appWidgetId;
		
		public void setFavIconDownloadUrl(String favIconDownloadUrl) {
			this.favIconDownloadUrl = favIconDownloadUrl;
		}
		public String getFavIconDownloadUrl() {
			return favIconDownloadUrl;
		}
		public void setRemoteViews(RemoteViews remoteViews) {
			this.remoteViews = remoteViews;
		}
		public RemoteViews getRemoteViews() {
			return remoteViews;
		}
		public void setRssFeedLinkUrl(String rssFeedLinkUrl) {
			this.rssFeedLinkUrl = rssFeedLinkUrl;
		}
		public String getRssFeedLinkUrl() {
			return rssFeedLinkUrl;
		}
		public void setContext(Context context) {
			this.context = context;
		}
		public Context getContext() {
			return context;
		}
		public void setAppWidgetId(int appWidgetId) {
			this.appWidgetId = appWidgetId;
		}
		public int getAppWidgetId() {
			return appWidgetId;
		}
		
	}
	

}
